﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace ShootMan
{
    //游戏服务器开启入口类
    public class GameServerEntry : MonoBehaviour
    {
        [SerializeField]
        private string _ipListen = "127.0.0.1";

        [SerializeField]
        private int _portListen = 8888;

        private System.Net.Sockets.TcpClient _lastConnectedClient = null;
        private shaco.Base.Net.ServerTCP _tcpServer = null;
        private shaco.Base.DataBuffer _netSendBuffer = new shaco.Base.DataBuffer();
        private shaco.Base.DataBuffer _netReceiveBuffer = new shaco.Base.DataBuffer();

        void Start()
        {
            //服务器限制为30帧
            Application.targetFrameRate = 30;
            StartServer();
        }

        void OnGUI()
        {
            if (DrawButton("Send Test"))
            {
                if (null != _tcpServer)
                {
                    var dataTmp = new shaco.Base.DataBuffer();
                    var sendData = new NetEvent.C2S_Test();
                    for (int i = 0; i < 1; ++i)
                    {
                        var messageTmp = "【Test】 I'm a server, ip=" + _ipListen + " port=" + _portListen + " index=" + i;

                        sendData.message = messageTmp;
                        NetEvent.NetHelper.WriteHeaderAndBody(dataTmp, new NetEvent.HeaderData()
                        {
                            messageID = sendData.messageID,
                            uuid = NetEvent.HeaderData.NewUUID(),
                        }, sendData);

                        _tcpServer.SendAll(dataTmp.ToBytes());
                    }
                }
                else
                    shaco.Log.Error("GameServerEntry Send Test erorr: server not start");
            }

            if (DrawButton("Disconnect last conencted client"))
            {
                if (null != _lastConnectedClient)
                {
                    _lastConnectedClient.Client.Disconnect(false);
                    _lastConnectedClient = null;
                }
                else
                    shaco.Log.Error("GameServerEntry Disconnect Test erorr: no client connected");
            }

            if (DrawButton("Stop Server"))
            {
                StopServer();
            }
        }

        private void StartServer()
        {
            StopServer();

            shaco.Log.Info("GameServerEntry StartServer: ip=" + _ipListen + " port=" + _portListen);

            _tcpServer = new shaco.Base.Net.ServerTCP(_ipListen, _portListen);
            _tcpServer.Start();
            _tcpServer.DatagramReceived += new System.EventHandler<shaco.Base.Net.ServerTCP.TcpDatagramReceivedEventArgs<byte[]>>(OnServerReceiveDataCallBack);

            _tcpServer.ClientConnected += (sender, arg) =>
            {
                shaco.Log.Info("notify client connected result=" + arg.TcpClient.Client);
                if (null != arg.TcpClient && null != arg.TcpClient.Client)
                    _lastConnectedClient = arg.TcpClient;
            };

            _tcpServer.ClientDisconnected += (sender, arg) =>
            {
                shaco.Log.Info("notify client disconnected result=" + arg.TcpClient.Client);
            };
        }

        private void StopServer()
        {
            if (null != _tcpServer)
            {
                shaco.Log.Info("Server will stop");
                _tcpServer.Stop();
                _tcpServer = null;
            }
            else
                shaco.Log.Info("Server is already stopped");
        }

        private void SendMessage(shaco.Base.DataBuffer data, System.Net.Sockets.TcpClient client)
        {
            if (null != client)
                _tcpServer.Send(client, data.ToBytes());
            else
                _tcpServer.SendAll(data.ToBytes(), client);
        }

        private void OnServerReceiveDataCallBack(object sender, shaco.Base.Net.ServerTCP.TcpDatagramReceivedEventArgs<byte[]> arg)
        {
            _netReceiveBuffer.ReWriteBytes(arg.Datagram);

            NetEvent.HeaderData header;
            NetEvent.INetEvent body = null;
            NetEvent.NetHelper.ReadHeaderAndBody(_netReceiveBuffer, out header, out body);

            shaco.Log.Info("GameServerEntry OnServerReceiveDataCallBack: messageID=" + header.messageID);

            //发回事件到客户端
            SendNetEventIfNeed(header, body, arg);
        }

        private void SendNetEventIfNeed(NetEvent.HeaderData headerData, NetEvent.INetEvent receiveEvent, shaco.Base.Net.ServerTCP.TcpDatagramReceivedEventArgs<byte[]> arg)
        {
            var sendEvent = shaco.Base.Utility.Instantiate(NetEvent.NetHelper.GetS2CEventTypeName(headerData.messageID)) as NetEvent.INetEvent;
            if (null != sendEvent)
            {
                var notifyEvent = sendEvent as NetEvent.S2C_INotifyEventType;
                System.Net.Sockets.TcpClient targetTCPClient = null;
                if (null != notifyEvent)
                {
                    notifyEvent.WriteNotifyData(receiveEvent);
                    targetTCPClient = null;
                }
                else
                    targetTCPClient = arg.TcpClient;

                NetEvent.NetHelper.WriteHeaderAndBody(_netSendBuffer, headerData, sendEvent);
                SendMessage(_netSendBuffer, targetTCPClient);
            }
        }

        private bool DrawButton(string title)
        {
            return GUILayout.Button(title, GUILayout.MaxHeight(Screen.height));
        }
    }
}